#pragma once 
#include "eventloop.hpp"

//线程与eventloop的结合
class LoopThread
{
private:
    // _loop需要在新创建的线程内部进行创建，当创建成功时候通过_cond信号量标明可以获取loop
    void ThreadEntry()
    {
        EventLoop loop;
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            _loop = &loop;
            _cond.notify_all();
        }
        loop.Start();
    }

public:
    LoopThread()
    : _thread(std::thread(&LoopThread::ThreadEntry, this))
    { }

    EventLoop* GetLoop() 
    { 
        // _loop是在新创建的内部进行创建的，因此GetLoop函数的调用可能早于_loop的创建，因此需要在_loop创建成功后(通过信号量得知)获取_loop
        EventLoop* loop = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            _cond.wait(lock, [&]() { return _loop != nullptr; });
            loop = _loop;
        }
        return loop; 
    }

private:
    std::mutex _mutex;
    std::condition_variable _cond;
    std::thread _thread;
    EventLoop* _loop = nullptr;
};


class LoopThreadPool
{
public:
    LoopThreadPool(EventLoop* base_loop, size_t thread_count = 0)
    :_base_loop(base_loop), _thread_count(thread_count)
    { }

    void SetThreadCount(size_t thread_count) 
    { 
        _thread_count = thread_count; 
    }

    void Create()
    {
        if(_thread_count == 0)
            return;
        threads.resize(_thread_count);
        loops.resize(_thread_count);
        for(int i = 0 ; i < _thread_count ; i++)
        {
            threads[i] = new LoopThread();
            loops[i] = threads[i]->GetLoop();
        }
    }

    EventLoop* NextLoop()
    {
        if(_thread_count == 0)
            return _base_loop;
        _next_idx = (_next_idx + 1) % _thread_count;
        return loops[_next_idx];
    }

private:
    size_t _thread_count; //线程池大小为 0 时，所有的操作都需要由_base_loop进行处理，而不为 0 时，则由线程池中的线程进行处理(轮询)
    size_t _next_idx = 0; //用于轮询获取线程
    std::vector<LoopThread*> threads;
    EventLoop* _base_loop;
    std::vector<EventLoop*> loops;
};